<template>
  <div class="ttt-tabs">
    <div v-if="$slots.title" ref="tabsTitleDom" class="ttt-tabs-title" :class="{radius}">
      <slot name="title" :index="currentActive" />
      <div class="title-active" :style="titleActiveStyle">
        <span></span>
      </div>
    </div>
    <div ref="tabsWrapperDom" class="ttt-tabs-wrapper">
      <div class="ttt-tabs-content">
        <slot name="default" />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, provide, ref } from 'vue'
import BScroll from '@better-scroll/core'
import Slide from '@better-scroll/slide'
import mitt from 'mitt'
import type { PropType, Slots, CSSProperties } from 'vue'
import type { TabsMittEmit } from './TTab'
import type { Page } from '@better-scroll/slide/src/SlidePages'

BScroll.use(Slide)

const emits = defineEmits<{
  (e: 'update:modelValue', value: number): void
}>()
const props = defineProps({
  // Tab切换索引
  modelValue: {
    type: Number as PropType<number>,
    default: 0
  },
  // 圆角title
  radius: {
    type: Boolean as PropType<boolean>,
    default: false
  }
})
const slots = defineSlots<{
  title: () => Slots[]
  default: () => Slots[]
}>()

// tabMitt 通信
const tabsMitt: TabsMittEmit = mitt()
// 当前选中Tab
const currentActive = ref<number>(props.modelValue > slots.default().length - 1 ? 0 : props.modelValue)
// Tab Title
const tabsTitleDom = ref()
// Tab 滑动
const tabsWrapperDom = ref()
// 滑动插件
const tabsSlide = ref<BScroll>()
// 标题活跃组件
const titleActiveStyle = computed<CSSProperties>((): CSSProperties => {
  return {
    left: `${currentActive.value * 100 / slots.title().length}%`,
    width: `${100 / slots.title().length}%`
  }
})

provide('currentActive', computed(() => currentActive.value))
provide('tabsMittEmit', tabsMitt)

// Tab切换
const handleChange = (page: Page) => {
  currentActive.value = page.pageX
  emits('update:modelValue', currentActive.value)
}

// 初始化Tab
const initTabs = () => {
  if (!tabsTitleDom.value) return
  const children = Array.from(tabsTitleDom.value.children) as HTMLElement[]
  children.forEach((item: HTMLElement, index: number) => {
    if (item.className.includes('ttt-tabs-title-item')) {
      item.dataset.index = String(index)
    }
  })
}

// 初始化滑动
const initSlider = () => {
  if (!tabsWrapperDom.value) return
  tabsSlide.value = new BScroll(tabsWrapperDom.value, {
    scrollX: true,
    scrollY: false,
    slide: {
      loop: true,
      threshold: 0.1,
      speed: 400,
      listenFlick: true,
      autoplay: false,
      interval: 3000
    },
    click: true,
    momentum: false,
    bounce: false,
    probeType: 3
  })
  tabsSlide.value?.on('slideWillChange', handleChange)
  handleClickTabsTitle(currentActive.value)
}

// 点击Tab标题切换
const handleClickTabsTitle = (page: number) => {
  if (page > slots.default().length - 1) return
  tabsSlide.value?.goToPage(page, 0)
}

onMounted(() => {
  initTabs()
  initSlider()
  tabsMitt.on('click', handleClickTabsTitle)
})

onBeforeUnmount(() => {
  tabsMitt.off('click', handleClickTabsTitle)
})
</script>

<style scoped lang="scss">
.ttt-tabs {
  width: 100%;

  .ttt-tabs-title {
    position: relative;
    width: 690rem;
    height: 88rem;
    line-height: 88rem;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 20rem;
    border-radius: var(--base-rudias);
    background-color: #f2f2f2;

    &.radius {
      border-radius: 999999999rem;

      .title-active > span {
        border-radius: 999999999rem;
      }
    }

    .title-active {
      position: absolute;
      left: 0;
      top: 0;
      height: 100%;
      transition: left 0.2s;

      > span {
        margin: 5rem;
        width: calc(100% - 10rem);
        height: calc(100% - 10rem);
        display: inline-block;
        background-color: var(--theme-color);
        border-radius: var(--base-rudias);
      }
    }
  }

  .ttt-tabs-wrapper {
    width: 100%;
    height: 100%;
    min-height: 1rem;
    overflow: hidden;

    .ttt-tabs-content {
      width: 100%;
      height: 100%;
      display: flex;
    }
  }
}
</style>
